/**
 * Copyright (c) 2015-2030 by Beijing Yanlight Co., Ltd.
 * All rights reserved.
 */
package com.yanlight.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.beetl.ext.servlet.ServletGroupTemplate;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.yanlight.Constants;

/**
 * 
 *
 * @author haolw
 * @time 2017/06/28
 */
public abstract class WebUtil {
	private static String CHARSET = Constants.DEFAULT_CHARSET_NAME;
	private static final String HTTP_SLASH = "://";
	private static final String HTTP_PROTOCOL = "http" + HTTP_SLASH;
	private static final String HTTPS_PROTOCOL = "https" + HTTP_SLASH;
	private static final String LOCAL_IP_PROTOCOL = "127.0.0.1";
	private static final String LOCAL_HOST_PROTOCOL = "localhost";
	private static final String BROWSE_HEADER = "user-agent";
	private static final String WX_BROWSE_AGENT = "MicroMessenger";
	private static final String ALIPAY_BROWSE_AGENT = "AlipayClient";
	private static final String NO_SERVICE_HTML = "/WEB-INF/views/noService.html";

	public static Boolean apiRequest() {
		return apiRequest(getRequest());
	}

	public static Boolean apiRequest(HttpServletRequest request) {
		if (ajax(request)) {
			return true;
		} else if (devRequest(request)) {
			return true;
		}
		return false;
	}

	/**
	 * 判断请求是否是ajax
	 * 
	 * @param request
	 * @return
	 */
	public static Boolean ajax(HttpServletRequest request) {
		String requestType = request.getHeader("X-Requested-With");
		if (null != requestType && "XMLHttpRequest".equals(requestType)) {
			return true;
		}
		return false;
	}

	/**
	 * 
	 * @param request
	 * @return
	 */
	public static Boolean devRequest(HttpServletRequest request) {
		Enumeration<String> headerNames = request.getHeaderNames();
		while (headerNames.hasMoreElements()) {
			String headerName = headerNames.nextElement();
			if (Constants.TOKEN_NAME.equalsIgnoreCase(headerName)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 得到客户端请求ip
	 * 
	 * @return
	 */
	public static String getTerminalIp() {
		return getTerminalIp(getRequest());
	}

	/**
	 * 
	 * @param url
	 * @return
	 */
	public static boolean checkUrlStandard(String url) {
		if (StringUtils.isNotBlank(url)) {
			if (StringUtils.startsWith(url, HTTP_PROTOCOL)) {
				return true;
			}
			if (StringUtils.startsWith(url, HTTPS_PROTOCOL)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 
	 * @param url
	 * @return
	 */
	public static boolean checkLocalUrl(String url) {
		if (checkUrlStandard(url)) {
			String subUrl = StringUtils.substringAfter(url, HTTP_SLASH);
			if (StringUtils.startsWith(subUrl, LOCAL_IP_PROTOCOL)) {
				return true;
			}
			if (StringUtils.startsWith(subUrl, LOCAL_HOST_PROTOCOL)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 得到客户端请求ip
	 * 
	 * @param request
	 * @return
	 */
	public static String getTerminalIp(HttpServletRequest request) {
		String result = "";
		String heads[] = { "x-forwarded-for", "X-Forwarded-For", "Proxy-Client-IP", "WL-Proxy-Client-IP",
				"HTTP_X_FORWARDED_FOR" };
		for (String head : heads) {
			if (isEmpty(result) || "unknown".equalsIgnoreCase(result)) {
				result = request.getHeader(head);
			}
		}
		if (!isEmpty(result)) {
			if (result.indexOf(".") != -1) {
				Pattern pattern = Pattern.compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}");
				Matcher matcher = pattern.matcher(result);
				result = null;
				while (matcher.find()) {
					result = matcher.group(0);
					break;
				}
			} else {
				result = null;
			}

		}
		if (isEmpty(result) || "unknown".equalsIgnoreCase(result)) {
			result = request.getRemoteAddr();
		}
		return result;
	}

	/**
	 * 
	 * @param response
	 * @param content
	 */
	public static void renderText(HttpServletResponse response, String content) {
		render(response, content, "Content-Type", "text/html;charset=" + CHARSET);
	}

	/**
	 * 
	 * @param response
	 * @param obj
	 */
	public static void renderJson(HttpServletResponse response, Object obj) {
		renderJson(response, obj, CHARSET);
	}

	/**
	 * 
	 * @param response
	 * @param data
	 * @param charset
	 */
	public static void renderJson(HttpServletResponse response, Object data, String charset) {
		try {
			render(response, JsonUtil.toJson(data), "Content-Type", "text/json;charset=" + CHARSET);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 
	 * @param response
	 * @param content
	 * @param headerName
	 * @param headerValue
	 */
	public static void render(HttpServletResponse response, String content, String headerName, String headerValue) {
		response.addHeader(headerName, headerValue);
		response.setStatus(200);
		render(response, content);
	}

	/**
	 * 
	 * @param response
	 * @param content
	 */
	private static void render(HttpServletResponse response, String content) {
		try {
			PrintWriter pw = response.getWriter();
			pw.write(content);
			pw.flush();
			pw.close();
			return;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 跳转无服务
	 * 
	 * @param request
	 * @param response
	 */
	public static void forwardNoService(HttpServletRequest request, HttpServletResponse response) {
		try {
			ServletGroupTemplate.instance().render(NO_SERVICE_HTML, request, response);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		return;
	}

	/**
	 * 获取request中的报文体
	 * 
	 * @param request
	 * @return
	 */
	public static String getRequestPackets(HttpServletRequest request) {
		String result = "";
		try {
			BufferedReader reader = request.getReader();
			result = copyToString(reader);
		} catch (IOException e) {
			throw new IllegalArgumentException(e);
		}
		return result;
	}

	/**
	 * 是否为微信内置浏览器
	 * 
	 * @param request
	 * @return
	 */
	public static boolean isWxBrowse(HttpServletRequest request) {
		String userAgent = request.getHeader(BROWSE_HEADER);
		return userAgent.contains(WX_BROWSE_AGENT);
	}

	/**
	 * 是否为支付宝内置浏览器
	 * 
	 * @param request
	 * @return
	 */
	public static boolean isAlipayBrowse(HttpServletRequest request) {
		String userAgent = request.getHeader(BROWSE_HEADER);
		return userAgent.contains(ALIPAY_BROWSE_AGENT);
	}

	/**
	 * 
	 * @return
	 */
	public static HttpServletRequest getRequest() {
		return getRequestAttributes().getRequest();
	}

	/**
	 * 
	 * @return
	 */
	public static HttpServletResponse getResponse() {
		return getRequestAttributes().getResponse();
	}

	/**
	 * 
	 * @return
	 */
	public static HttpSession getSession() {
		HttpServletRequest request = getRequest();
		if (request == null) {
			return null;
		}
		return request.getSession();
	}

	/**
	 * 
	 * @return
	 */
	private static ServletRequestAttributes getRequestAttributes() {
		return (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
	}

	/**
	 * 
	 * @param context
	 * @return
	 */
	public static ApplicationContext getRootApplicationContext(ServletContext context) {
		String contextName = WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE;
		return (ApplicationContext) context.getAttribute(contextName);
	}

	/**
	 * 判断是否空
	 * 
	 * @param cs
	 * @return
	 */
	private static boolean isEmpty(CharSequence cs) {
		return cs == null || cs.length() == 0;
	}

	private static String copyToString(Reader in) throws IOException {
		StringWriter out = new StringWriter();
		copy(in, out);
		return out.toString();
	}

	private static int copy(Reader in, Writer out) throws IOException {
		try {
			int byteCount = 0;
			char[] buffer = new char[4096];
			int bytesRead = -1;
			while ((bytesRead = in.read(buffer)) != -1) {
				out.write(buffer, 0, bytesRead);
				byteCount += bytesRead;
			}
			out.flush();
			return byteCount;
		} finally {
			try {
				in.close();
			} catch (IOException ex) {
			}
			try {
				out.close();
			} catch (IOException ex) {
			}
		}
	}
}
